﻿package org.libspark.betweenas3.tickers
{
	import flash.display.Shape;
	import flash.events.Event;
	import flash.utils.getTimer;
	import org.libspark.betweenas3.core.ticker.ITicker;
	import org.libspark.betweenas3.core.ticker.TickerListener;
	
	/**
	 * 毎フレームコールバックを行う ITicker の実装です.
	 * 
	 * @author	yossy:beinteractive
	 */
	public class EnterFrameTicker implements ITicker
	{
		public function EnterFrameTicker()
		{
			var prevListener:TickerListener = null;
			
			// linked list initialize
			_tickerListenerPaddings = new Vector.<TickerListener>(10, true);
			for (var i:uint = 0; i < 10; ++i) {
				var listener:TickerListener = new TickerListener();
				if (prevListener != null)
				{
					prevListener.nextListener = listener;
					listener.prevListener = prevListener;
				}
				prevListener = listener;
				_tickerListenerPaddings[i] = listener;
			}
		}
		
		
		private static var _shape:Shape = new Shape();
		
		private var _first:TickerListener = null;
		private var _numListeners:uint = 0;
		private var _tickerListenerPaddings:Vector.<TickerListener>;
		private var _time:Number;
		

		public function get time():Number{return _time;}
		
		
		//=========================================================================
		// first（last inserted listener） - listener - listener - listener...
		//=========================================================================
		public function addTickerListener(listener:TickerListener):void
		{
			if (listener.nextListener != null || listener.prevListener != null)
			{
				return;
			}
			
			if (_first != null) {
				if (_first.prevListener != null) {
					_first.prevListener.nextListener = listener;
					listener.prevListener = _first.prevListener;
				}
				listener.nextListener = _first;
				_first.prevListener = listener;
			}
			
			_first = listener;
			
			++_numListeners;
		}
		

		public function removeTickerListener(listener:TickerListener):void
		{
			var l:TickerListener = _first;
			
			while (l != null) 
			{
				if (l == listener) 
				{
					if (l.prevListener != null) {
						l.prevListener.nextListener = l.nextListener;
						l.nextListener = null;
					}
					else {
						_first = l.nextListener;
					}
					if (l.nextListener != null) {
						l.nextListener.prevListener = l.prevListener;
						l.prevListener = null;
					}
					--_numListeners;
				}
				
				l = l.nextListener;
			}
		}
		

		public function start():void
		{
			_time = getTimer() / 1000;
			_shape.addEventListener(Event.ENTER_FRAME, update);
		}
		

		public function stop():void
		{
			_shape.removeEventListener(Event.ENTER_FRAME, update);
		}
		

		internal function update(e:Event):void
		{
			// リスナの数を 8 の倍数になるようにパディングして 8 個ずつ一気にループさせる
			
			var t:Number                 =  _time = getTimer() / 1000;
			var	n:uint                   =  8 - (_numListeners % 8);
			var listener:TickerListener  =  _tickerListenerPaddings[0];
			var l:TickerListener         =  _tickerListenerPaddings[n];
			var ll:TickerListener        =  null;
			
			// このようにつなぎかえることでパディングの数を変える
			if ((l.nextListener = _first) != null)
			{
				_first.prevListener = l;
			}
			
			// 下一节点
			while (listener.nextListener != null)
			{
				
				// 试运行
				if ((listener = listener.nextListener).tick(t))
				{
					// 跳过
					if (listener.prevListener != null)
					{
						listener.prevListener.nextListener = listener.nextListener;
					}
					
					if (listener.nextListener != null) 
					{
						listener.nextListener.prevListener = listener.prevListener;
					}
					
					// 移除
					ll = listener.prevListener;
					listener.nextListener = null;
					listener.prevListener = null;
					listener = ll;
					--_numListeners;
				}
				
				if ((listener = listener.nextListener).tick(t)) {
					if (listener.prevListener != null) {
						listener.prevListener.nextListener = listener.nextListener;
					}
					if (listener.nextListener != null) {
						listener.nextListener.prevListener = listener.prevListener;
					}
					ll = listener.prevListener;
					listener.nextListener = null;
					listener.prevListener = null;
					listener = ll;
					--_numListeners;
				}
				if ((listener = listener.nextListener).tick(t)) {
					if (listener.prevListener != null) {
						listener.prevListener.nextListener = listener.nextListener;
					}
					if (listener.nextListener != null) {
						listener.nextListener.prevListener = listener.prevListener;
					}
					ll = listener.prevListener;
					listener.nextListener = null;
					listener.prevListener = null;
					listener = ll;
					--_numListeners;
				}
				if ((listener = listener.nextListener).tick(t)) {
					if (listener.prevListener != null) {
						listener.prevListener.nextListener = listener.nextListener;
					}
					if (listener.nextListener != null) {
						listener.nextListener.prevListener = listener.prevListener;
					}
					ll = listener.prevListener;
					listener.nextListener = null;
					listener.prevListener = null;
					listener = ll;
					--_numListeners;
				}
				if ((listener = listener.nextListener).tick(t)) {
					if (listener.prevListener != null) {
						listener.prevListener.nextListener = listener.nextListener;
					}
					if (listener.nextListener != null) {
						listener.nextListener.prevListener = listener.prevListener;
					}
					ll = listener.prevListener;
					listener.nextListener = null;
					listener.prevListener = null;
					listener = ll;
					--_numListeners;
				}
				if ((listener = listener.nextListener).tick(t)) {
					if (listener.prevListener != null) {
						listener.prevListener.nextListener = listener.nextListener;
					}
					if (listener.nextListener != null) {
						listener.nextListener.prevListener = listener.prevListener;
					}
					ll = listener.prevListener;
					listener.nextListener = null;
					listener.prevListener = null;
					listener = ll;
					--_numListeners;
				}
				if ((listener = listener.nextListener).tick(t)) {
					if (listener.prevListener != null) {
						listener.prevListener.nextListener = listener.nextListener;
					}
					if (listener.nextListener != null) {
						listener.nextListener.prevListener = listener.prevListener;
					}
					ll = listener.prevListener;
					listener.nextListener = null;
					listener.prevListener = null;
					listener = ll;
					--_numListeners;
				}
				if ((listener = listener.nextListener).tick(t)) {
					if (listener.prevListener != null) {
						listener.prevListener.nextListener = listener.nextListener;
					}
					if (listener.nextListener != null) {
						listener.nextListener.prevListener = listener.prevListener;
					}
					ll = listener.prevListener;
					listener.nextListener = null;
					listener.prevListener = null;
					listener = ll;
					--_numListeners;
				}
			}
			
			// 元に戻す
			if ((_first = l.nextListener) != null) 
			{
				_first.prevListener = null;
			}
			l.nextListener = _tickerListenerPaddings[n + 1];
		}
	}
}